use crate::ethvm::DzkAccount;
use ethereum_types::{H160, H256, U256};
use serde::{Deserialize, Serialize};
use vsdb::{MapxDkVs, MapxVs, Vs};

pub const DECIMAL: u32 = 18;

#[derive(Vs, Clone, Default, Debug, Deserialize, Serialize)]
pub struct Erc20Like {
    pub accounts: MapxVs<H160, DzkAccount>,

    // (addr, key) => value
    pub storages: MapxDkVs<H160, H256, H256>,
}

impl Erc20Like {
    /// Get the handler of an account.
    #[inline(always)]
    pub fn native_account(&self, addr: H160) -> Option<DzkAccount> {
        self.accounts.get(&addr)
    }

    /// Get the balance of native token.
    #[inline(always)]
    pub fn native_balance(&self, addr: H160) -> U256 {
        self.native_account(addr)
            .map(|acc| acc.balance)
            .unwrap_or_default()
    }

    /// Check if the balance of native token is bigger than or equal to the target amount.
    #[inline(always)]
    pub fn native_balance_be(&self, addr: H160, target_amount: U256) -> (bool, U256) {
        let balance = self.native_balance(addr);
        (balance >= target_amount, balance)
    }

    #[inline(always)]
    pub fn nonce(&self, addr: H160) -> U256 {
        self.native_account(addr)
            .map(|acc| acc.nonce)
            .unwrap_or_else(U256::zero)
    }

    #[inline(always)]
    pub fn nonce_is_valid(&self, addr: H160, nonce: U256) -> bool {
        self.nonce(addr) == nonce
    }
}
